﻿#pragma once

#include <GL/gl3w.h>
#include <GLFW/glfw3.h>

#include <agent/agent.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define	STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#include <stb_image.h>

#include <Saba/Base/Path.h>
#include <Saba/Base/File.h>
#include <Saba/Base/UnicodeUtil.h>
#include <Saba/Base/Time.h>
#include <Saba/Model/MMD/PMDModel.h>
#include <Saba/Model/MMD/PMXModel.h>
#include <Saba/Model/MMD/VMDFile.h>
#include <Saba/Model/MMD/VMDAnimation.h>
#include <Saba/Model/MMD/VMDCameraAnimation.h>

#define IMGUI_IMPL_OPENGL_LOADER_GL3W
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>

class AppContext;
class Model;
class MMDShader;
class MMDEdgeShader;
class MMDGroundShadowShader;

#include <mmd/Material.h>
#include <mmd/MMDGroundShadowShader.h>
#include <mmd/MMDShader.h>
#include <mmd/MMDEdgeShader.h>
#include <mmd/Model.h>

GLuint CreateShader(GLenum shaderType, const string code);
GLuint CreateShaderProgram(const string vsFile, const string fsFile);

class Texture
{
public:
	GLuint	m_texture;
	bool	m_hasAlpha;
};

class AppContext : public IAgentComponent,Config
{
public:
	AppContext();
	~AppContext(){};
	static AppContext * getInstance();

	string m_resourceDir;
	string	m_shaderDir;
	string	m_mmdDir;

	unique_ptr<MMDShader>				m_mmdShader;
	unique_ptr<MMDEdgeShader>			m_mmdEdgeShader;
	unique_ptr<MMDGroundShadowShader>	m_mmdGroundShadowShader;

	glm::mat4	m_viewMat;
	glm::mat4	m_projMat;
	int			m_screenWidth = 0;
	int			m_screenHeight = 0;
	GLFWwindow * window = nullptr;

	glm::vec3	m_lightColor = glm::vec3(0.5f, 0.5f, 0.5f);
	glm::vec3	m_lightDir = glm::vec3(-0.5f, -1.0f, -0.5f);

	bool show_shadow = false;
	bool show_edge = false;

	map<string, Texture>	m_textures;
	GLuint	m_dummyColorTex = 0;
	GLuint	m_dummyShadowDepthTex = 0;

	float	m_elapsed = 0.0f;
	float	m_animTime = 0.0f;
	double	saveTime = 0.0f;
	unique_ptr<saba::VMDCameraAnimation>	m_vmdCameraAnim;

	void Update();
	void Init();
	void BeforeEnd();
	void BeforeUpdate();
	void PollMessage(Message message);

	Texture GetTexture(const string& texturePath,bool flip = true);

	void DeleteModel(const string key);//multithread unsafe
    bool AddModel(const string key,const string modelPath,const glm::vec3 & t);//multithread safe
	//void SetAnimation(const string key,shared_ptr<saba::VMDAnimation> m_anim,bool loop);
	//shared_ptr<saba::VMDAnimation> GetAnimation(const string key,const string vmdPath);
	saba::VMDFile GetAnimation(const string vmdPath);
	void SetAnimation(const string key,saba::VMDFile & m_anim,bool loop,bool clear);
	void SetAnimation(const string key,const string m_anim_key,bool loop,bool clear);

	bool isAnimEnd(string key);
    
    constexpr const static float FPS = 30.0f;
private:
	//shared_ptr<saba::VMDAnimation> testAnim;
	map<string,saba::VMDFile> vmds;
	string cur_anim;
	map<string,Model> models;

	static AppContext * m_instance;

	float sum_idle_time = 0.0f;

	saba::MMDMorph * month,*eye;
	bool month_enable = false;
	float month_speed = 12.0f;
	float Blink_speed = 15.0f;
	bool Blink_enable = false;
	float Blink_last = 0.2f;
	float Blink_time = 0.0f;
	float Blink_interval = 2.0f;

	bool showPanel = false;
private:
	void InitMorph();
	void autoPlayIdle();
	void autoMonth();
	void autoBlink();
	void DrawPanel();
};
